package com.mrx.commons.util.redis;

import com.mrx.commons.util.LambdaUtil;
import com.mrx.commons.util.redis.adapter.FakeOperationsAdapter;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.lang.NonNull;

import java.util.Map;
import java.util.concurrent.TimeUnit;

public class FakeValueOperations<K, V> extends FakeOperationsAdapter<K, V> {

    private static final Logger logger = LoggerFactory.getLogger(FakeValueOperations.class);

    private final Map<Object, ValueWrapper> fakeRedis;

    public FakeValueOperations(Map<Object, ValueWrapper> fakeRedis) {
        this.fakeRedis = fakeRedis;
        new Thread() {
            {
                setName("expireTask");
            }

            @Override
            @SneakyThrows
            @SuppressWarnings({"InfiniteLoopStatement", "BusyWait"})
            public void run() {
                while (true) {
                    long measure = LambdaUtil.runMeasure(() -> {
                        logger.trace("开始检测 是否存在过期 key");
                        fakeRedis.forEach((k, v) -> {
                            if (v.isExpired()) {
                                logger.info("移除 过期 key: {} -> {}", k, v);
                                fakeRedis.remove(k);
                            }
                        });
                    });
                    logger.trace("一轮检测完毕, 花费: {} ms, 当前 key: {}", measure, fakeRedis);
                    Thread.sleep(1000);
                }
            }
        }.start();
    }

    @Override
    @SuppressWarnings("unchecked")
    public V get(@NonNull Object key) {
        ValueWrapper wrapper = fakeRedis.get(key);
        return wrapper == null ? null : (V) wrapper.getObj();
    }

    @Override
    public void set(@NonNull K key, @NonNull V value, long timeout, @NonNull TimeUnit unit) {
        fakeRedis.put(key, ValueWrapper.of(value).setTimeout(timeout).setUnit(unit));
    }

    @Override
    public Boolean delete(@NonNull K key) {
        boolean res = fakeRedis.containsKey(key);
        fakeRedis.remove(key);
        logger.debug("删除 key: {}", key);
        return res;
    }

    @Override
    public Boolean expire(@NonNull K key, long timeout, @NonNull TimeUnit unit) {
        fakeRedis.get(key).setTimeout(timeout).setUnit(unit);
        return true;
    }

    @Override
    public void set(@NonNull K key, @NonNull V value) {
        logger.debug("fakeSet: {} -> {}", key, value);
        fakeRedis.put(key, ValueWrapper.of(value));
        logger.debug("currentFakeRedis: {}", fakeRedis);
    }

    @Override
    public V getAndDelete(@NonNull K key) {
        V v = get(key);
        delete(key);
        return v;
    }

}
